package infra;

import business.User;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;

public class FileUserDAO implements InterfaceUserDAO
{

    // Constants 
    private final String PATH = File.separator + "Application" + File.separator + "users.data";

    // Variables frequently used
    private File dataFile;
    private FileOutputStream fout;
    private FileInputStream fins;
    private ObjectOutputStream oos;
    private ObjectInputStream ois;

    //Temporary list file
    private LinkedList<User> users;

    //Instance of FileUserDAO
    private static FileUserDAO instance;

    private FileUserDAO() throws IOException
    {
        dataFile = new File(PATH);
        try
        {
            if (dataFile.exists())
            {
                dataFile.mkdirs();
                dataFile.createNewFile();
            }
            getAll();
        }
        catch (IOException | ClassNotFoundException erro)
        {
            throw new IOException("Erro ao pegar/criar arquivo em " + PATH);
        }
    }

    /**
     * Get a singleton instance of FileUserDAO
     *
     * @return the only instance
     * @throws IOException
     */
    public static FileUserDAO getInstance() throws IOException
    {
        if (instance == null)
        {
            instance = new FileUserDAO();
        }
        return instance;
    }

    @Override
    public boolean createUser(User user)
    {
        users.add(user);

        try
        {
            fout = new FileOutputStream(dataFile);
            oos = new ObjectOutputStream(fout);

            oos.flush();
            oos.writeObject(users);
            oos.close();
            fout.close();
            return true;
        }
        catch (IOException error)
        {
            return false;
        }
    }

    ;

    /**
     * Get an user from file, if IP doent exist, return null
     * @param IP computer's ip from the user
     * @return the user
     * @throws Exception if file not found
     */
    @Override
    public User retrieveUser(String IP) throws Exception
    {
        User user = null;
        try
        {
            fins = new FileInputStream(dataFile);
            ois = new ObjectInputStream(fins);
            fins.reset();

            users = (LinkedList<User>) ois.readObject(); //pega a lista do arquivo
            for (User userFromList : users) //varre a lista até encontrar o usuario
            {
                if (userFromList.getIP().equals(IP)) //se encontrar
                {
                    user = userFromList; //substitui e sai
                    break;
                }
            }

            ois.close();
            fins.close();
            return user;
        }
        catch (IOException | ClassNotFoundException erro)
        {
            throw erro;
        }
    }

    @Override
    public boolean updateUser(User userUpdated, String ip)
    {
        for (User userFromList : users) //varre a lista até encontrar o usuario
        {
            if (userFromList.getIP().equals(ip)) //se encontrar
            {
                userFromList = userUpdated; //substitui e sai
                break;
            }
        }
        try
        {
            fout = new FileOutputStream(dataFile);
            oos = new ObjectOutputStream(fout);

            oos.flush();
            oos.writeObject(users);
            oos.close();
            fout.close();
            return true;
        }
        catch (IOException error)
        {
            return false;
        }
    }

    @Override
    public boolean deleteUser(String IP)
    {
        for (User userFromList : users) //varre a lista até encontrar o usuario
        {
            if (userFromList.getIP().equals(IP)) //se encontrar
            {
                users.remove(userFromList);
                break;
            }
        }
        try
        {
            fout = new FileOutputStream(dataFile);
            oos = new ObjectOutputStream(fout);

            oos.flush();
            oos.writeObject(users);
            oos.close();
            fout.close();
            return true;
        }
        catch (IOException error)
        {
            return false;
        }

    }

    /**
     * Get all users from file
     *
     * @return the list of users
     * @throws IOException file not found
     * @throws ClassNotFoundException User class not found
     */
    @Override
    public LinkedList<User> getAll() throws IOException, ClassNotFoundException
    {
        if (dataFile.length() == 0) //tá vazio
        {
            return this.users = new LinkedList<User>(); //salva e retorna
        }
        try
        {
            fins = new FileInputStream(dataFile);
            ois = new ObjectInputStream(fins);
            fins.reset();
            this.users = (LinkedList<User>) ois.readObject(); //pega a lista do arquivo
            ois.close();
            fins.close();
            return this.users;
        }
        catch (IOException | ClassNotFoundException erro)
        {
            throw erro;
        }

    }
}
